package com.own.component.util.excel.util.read;

import com.own.component.util.excel.util.read.base.AbstractExcelRead;
import com.own.component.util.excel.util.read.base.BaseExcelReadConfig;
import com.own.component.util.excel.util.read.config.ExcelReadCustomConfig;
import com.own.component.util.excel.util.read.config.ExcelReadLineConfig;
import com.own.component.util.excel.util.read.config.ExcelReadMultipleConfig;
import com.own.component.util.excel.util.read.function.resolve.CustomResolveFunction;
import com.own.component.util.excel.util.read.function.resolve.MultipleResolveFunction;
import com.own.component.util.excel.util.read.function.resolve.ResolveFunction;
import com.own.component.util.excel.util.read.model.ResolveFileModel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * ExcelReadMultiple
 *
 * @author chenxueli
 * @date 2022-10-07 13:21:00
 */
@Slf4j
public class ExcelReadMultiple<T> extends AbstractExcelRead<T, MultipleResolveFunction, ExcelReadMultipleConfig<T>> {

    private final List<Custom<T>> customList;

    private final List<Normal<T>> normalList;

    private boolean zip;

    public ExcelReadMultiple() {
        customList = new ArrayList<>();
        normalList = new ArrayList<>();
        zip = false;
    }

    /**
     * 读取excel内容
     *
     * @param file 文件
     * @return 解析后的内容信息
     */
    public final List<T> read(MultipartFile file) {
        return read(new ResolveFileModel(file));
    }

    /**
     * 读取excel内容
     *
     * @param path 文件路径
     * @return 解析后的内容信息
     */
    public final List<T> read(String path) {
        return read(new ResolveFileModel(path));
    }

    /**
     * 读取excel内容
     *
     * @param file 文件
     * @return 解析后的内容信息
     */
    public final List<T> read(File file) {
        return read(new ResolveFileModel(file));
    }

    /**
     * 读取excel内容
     *
     * @param inputStream 文件流
     * @return 解析后的内容信息
     */
    public final List<T> read(InputStream inputStream) {
        return read(new ResolveFileModel(inputStream));
    }

    /**
     * 读取excel内容
     *
     * @param fileModel 文件信息
     * @return 解析后的内容信息
     */
    public final List<T> read(ResolveFileModel fileModel) {
        return read(fileModel, null);
    }

    /**
     * 读取excel内容
     *
     * @param fileModel       文件信息
     * @param resolveFunction 解析数据的方法
     * @return 解析后的内容信息
     */
    @Override
    public List<T> read(ResolveFileModel fileModel, MultipleResolveFunction resolveFunction) {
        // 获取工作表
        var sheet = getSheet(fileModel.newInputStream());
        // 获取解析方法
        for (var item : customList) {
            var flag = item.getCheck().apply(sheet);
            if (flag) {
                var resultConfig = getResultConfig(item);
                return zip
                        ? new ExcelReadIfZipCustom<T>().config(resultConfig).read(fileModel, item.getFun())
                        : new ExcelReadCustom<T>().config(resultConfig).read(fileModel, item.getFun());
            }
        }
        for (var item : normalList) {
            var flag = item.getCheck().apply(sheet);
            if (flag) {
                var resultConfig = getResultConfig(item);
                return zip
                        ? new ExcelReadIfZip<T>().config(resultConfig).read(fileModel, item.getFun())
                        : new ExcelRead<T>().config(resultConfig).read(fileModel, item.getFun());
            }
        }
        return new ArrayList<>();
    }

    /**
     * 获取配置信息
     *
     * @param parent 配置信息
     * @return 工作表
     */
    private <CONFIG extends BaseExcelReadConfig<T>> CONFIG getResultConfig(AbstractParentCheck<T, CONFIG> parent) {
        if (parent.getConfig() != null) {
            return parent.getConfig();
        }
        if (parent.getConfigFunction != null) {
            return parent.getConfigFunction.get();
        }
        return null;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, CustomResolveFunction<T> fun) {
        customList.add(new Custom<>(check, fun));
        return this;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, ExcelReadCustomConfig<T> config, CustomResolveFunction<T> fun) {
        var item = new Custom<>(check, fun);
        item.setConfig(config);
        customList.add(item);
        return this;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, Supplier<ExcelReadCustomConfig<T>> config, CustomResolveFunction<T> fun) {
        var item = new Custom<>(check, fun);
        item.setGetConfigFunction(config);
        customList.add(item);
        return this;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, ResolveFunction<T> fun) {
        normalList.add(new Normal<>(check, fun));
        return this;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, ExcelReadLineConfig<T> config, ResolveFunction<T> fun) {
        var item = new Normal<>(check, fun);
        item.setConfig(config);
        normalList.add(item);
        return this;
    }

    /**
     * 追加解析方法
     *
     * @param check 验证方法
     * @param fun   解析方法
     */
    public ExcelReadMultiple<T> put(Function<Sheet, Boolean> check, Supplier<ExcelReadLineConfig<T>> config, ResolveFunction<T> fun) {
        var item = new Normal<>(check, fun);
        item.setGetConfigFunction(config);
        normalList.add(item);
        return this;
    }

    /**
     * 设置为允许zip
     */
    public void allowZip() {
        this.zip = true;
    }

    /**
     * 获取默认的配置信息
     *
     * @return 默认的配置信息
     */
    @Override
    protected ExcelReadMultipleConfig<T> getDefaultConfig() {
        return new ExcelReadMultipleConfig<T>();
    }

    @Getter
    private static abstract class AbstractParentCheck<T, CONFIG extends BaseExcelReadConfig<T>> {
        /**
         * 验证方法
         */
        private final Function<Sheet, Boolean> check;

        /**
         * 配置信息
         */
        @Setter
        private CONFIG config;

        /**
         * 配置信息de方法
         */
        @Setter
        private Supplier<CONFIG> getConfigFunction;

        public AbstractParentCheck(Function<Sheet, Boolean> check) {
            this.check = check;
        }

    }

    @Getter
    private static class Custom<T> extends AbstractParentCheck<T, ExcelReadCustomConfig<T>> {

        private final CustomResolveFunction<T> fun;

        public Custom(Function<Sheet, Boolean> check, CustomResolveFunction<T> fun) {
            super(check);
            this.fun = fun;
        }
    }

    @Getter
    private static class Normal<T> extends AbstractParentCheck<T, ExcelReadLineConfig<T>> {

        private final ResolveFunction<T> fun;

        public Normal(Function<Sheet, Boolean> check, ResolveFunction<T> fun) {
            super(check);
            this.fun = fun;
        }
    }
}
